using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using zeroflag.Windows.Custom;

namespace zeroflag.Parserz.IDE
{
	public partial class TokenController : TreeController<ACustomView, TokenNode>
	{
		public TokenController()
		{
			this.InitializeComponent();
		}

		public TokenController(ACustomView view)
			: base(view)
		{
		}

		#region Properties
		Size m_CharSize = new Size(14, 14);

		[System.ComponentModel.Category("Tokens")]
		public Size CharSize
		{
			get { return m_CharSize; }
			set { m_CharSize = value; }
		}
		ColorCombi m_ColorCombi = new ColorCombi();

		[System.ComponentModel.Category("Tokens")]
		public ColorCombi ColorCombi
		{
			get { return m_ColorCombi; }
			set { m_ColorCombi = value; }
		}
		private Dictionary<Type, ColorCombi> m_TokenColors = new Dictionary<Type, ColorCombi>();

		[System.ComponentModel.Category("Tokens")]
		public Dictionary<Type, ColorCombi> TokenColors
		{
			get { return m_TokenColors; }
			set { m_TokenColors = value; }
		}
		Font m_Font = new Font(FontFamily.GenericMonospace, 12, FontStyle.Regular, GraphicsUnit.Pixel);

		[System.ComponentModel.Category("Tokens")]
		public Font Font
		{
			get { return m_Font; }
			set { m_Font = value; }
		}
		Padding m_Margin = new Padding(0, 0, 0, 0);

		[System.ComponentModel.Category("Tokens")]
		public Padding Margin
		{
			get { return m_Margin; }
			set { m_Margin = value; }
		}
		Padding m_Padding = new Padding(0, 0, 0, 0);

		[System.ComponentModel.Category("Tokens")]
		public Padding Padding
		{
			get { return m_Padding; }
			set { m_Padding = value; }
		}
		Pen m_PenSelected = Pens.Red;

		[System.ComponentModel.Category("Tokens")]
		public Pen PenSelected
		{
			get { return m_PenSelected; }
			set { m_PenSelected = value; }
		}
		Control m_RenderTarget;

		[System.ComponentModel.Category("Tokens")]
		public Control RenderTarget
		{
			get { return m_RenderTarget; }
			set { m_RenderTarget = value; }
		}
		private zeroflag.Parserz.Token m_Root;

		[System.ComponentModel.Category("Tokens")]
		public zeroflag.Parserz.Token Root
		{
			get { return m_Root; }
			set
			{
				if (m_Root != value)
				{
					if (m_Root != null)
					{
						m_Root.Changed -= this.TokenChanged;
					}
					m_Root = value;
					if (m_Root != null)
					{
						m_Root.Changed += this.TokenChanged;
					}
					this.RebuildGraph();
				}
			}

		}
		TokenNode m_TokenGraph;

		[System.ComponentModel.Category("Tokens")]
		public TokenNode TokenGraph
		{
			get { return m_TokenGraph; }
			set { m_TokenGraph = value; }
		}
		List<TokenNode> m_SelectedNodes = new List<TokenNode>();

		[System.ComponentModel.Category("Tokens")]
		public List<TokenNode> SelectedNodes
		{
			get { return m_SelectedNodes; }
			set { m_SelectedNodes = value; }
		}
		Dictionary<Token, TokenNode> m_Nodes = new Dictionary<Token, TokenNode>();

		[System.ComponentModel.Category("Tokens")]
		public Dictionary<Token, TokenNode> Nodes
		{
			get { return m_Nodes; }
			set { m_Nodes = value; }
		}
		protected const int SelectRangeLimit = 10000;

		[System.ComponentModel.Category("Tokens")]
		public ColorCombi this[Token token]
		{
			get
			{
				if (this.TokenColors.ContainsKey(token.GetType()))
				{
					return this.TokenColors[token.GetType()];
				}
				else
				{
					// initialize with default colors...
					this.TokenColors.Add(token.GetType(), new ColorCombi());
					return this.TokenColors[token.GetType()];
				}
			}
			set
			{
				if (this.TokenColors.ContainsKey(token.GetType()))
				{
					this.TokenColors[token.GetType()] = value;
				}
				else
				{
					// initialize with default colors...
					this.TokenColors.Add(token.GetType(), value);
				}
			}
		}
		#endregion Properties

		public void TokenChanged(Token token)
		{
			this.RenderTarget.BeginInvoke(new MethodInvoker(this.RebuildGraph));
		}

		public void HandleMouseSelect(int x, int y)
		{
			TokenNode node = this.TokenGraph.Find(x, y);
			List<TokenNode> range = new List<TokenNode>();
			bool add = true;
			if (Form.ModifierKeys == Keys.Shift)
			{
				if (node != null)
				{
					if (this.SelectedNodes.Count > 0)
					{
						TokenNode last = this.SelectedNodes[this.SelectedNodes.Count - 1];
						range.Clear();
						this.SelectRange(last, node, range);

						if (!this.SelectedNodes.Contains(node))
						{
							// node not selected yet, add range to selection...
						}
						else
						{
							// node already selected, remove from selection...
							add = false;
						}
					}
				}
				else
				{
					// nothing selected, do nothing...
					return;
				}
			}
			else if (Form.ModifierKeys == Keys.Control)
			{
				// add node to selection...
				if (node == null)
				{
					// nothing selected, do nothing...
					return;
				}
			}
			else
			{
				// select only node...
				this.SelectedNodes.Clear();
			}
			if (add)
				this.SelectedNodes.AddRange(range);
			else
				foreach (TokenNode n in range)
					this.SelectedNodes.Remove(n);

			if (node != null)
			{
				if (add)
					this.SelectedNodes.Add(node);
				else
					this.SelectedNodes.Remove(node);
			}
			else
			{
			}
			//this.ApplySelects();
		}

		protected delegate TokenNode NextNode(TokenNode current);
		protected List<TokenNode> SelectRange(TokenNode start, TokenNode end, List<TokenNode> range)
		{
			if (start != null)
			{
				range.Add(start);
			}
			else
				return range;

			TokenNode current = start;
			NextNode next;
			if (start.Token.Index < end.Token.Index)
				// search forward
				next = delegate(TokenNode c) { return c.Right; };
			else
				// search backwards...
				next = delegate(TokenNode c) { return c.Left; };

			for (int i = 0; i < SelectRangeLimit && current != end && current != null; i++)
			{
				current = next(current);
				if (start != null)
				{
					range.Add(current);
				}
			}
			return range;
		}

		public void RebuildGraph()
		{
			this.TokenGraph = new TokenNode(this, null, this.Root);
			if (this.RenderTarget != null)
				this.RenderTarget.Invalidate();
		}

		public override void Render(RenderArea renderArea)
		{
			base.Render(renderArea);
			if (this.TokenGraph == null)
				this.RebuildGraph();
			if (this.TokenGraph != null)
				this.TokenGraph.Render(renderArea);
		}
	}
}
